import type {
	DecimalAdjustType,
} from './type';
import {
	simpleSplitString,
} from '../string';
//region numberIsFinite
/**
 * 判断数字是不是有限的(同Number.isFinite)
 * @param num	判断的数字
 */
function numberIsFinite(num:number):boolean{
	return num===num&&num!==Infinity&&num!==-Infinity;
}
//endregion
//region numberIsInteger
/**
 * 判断数字是不是整数(同Number.IsInteger)
 * @param num	判断的数字
 */
function numberIsInteger(num:number):boolean{
	return numberIsFinite(num)&&Math.floor(num)===num;
}
//endregion
//region decimalDigits
/**
 * 获取小数位数
 * 传入一个实数, 返回该实数的小数位数
 * @param number	传入的实数
 * @return			小数位数
 */
function decimalDigits(number:number|string):number{
	if(typeof number==='string'){
		number=Number(number);
	}
	if(!numberIsFinite(number)){
		return NaN;
	}
	number=number+'';
	const p1=number.indexOf('.');
	const p2=number.indexOf('e');
	if(p2!==-1){
		let decimal=p1===-1?0:p2-p1-1;
		decimal-=Number(number.slice(p2+1));
		return decimal<0?0:decimal;
	}
	return p1===-1?0:number.length-p1-1;
}
//endregion
//region numberRound、numberCeil、numberFloor
/**
 * 适配 Math.round ,Math.ceil ,Math.floor 带小数位数的版本
 * @param type		类型
 * @param number	取整的数
 * @param digits	小数位数
 * @return			取整后的数
 */
function _decimalAdjust(type:DecimalAdjustType,number:number,digits?:number):number{
	const fn=Math[type];
	if(digits===undefined||digits===0||number===0||!numberIsFinite(number)){
		return fn(number);
	}else if(digits===Infinity){
		return number;
	}else if(digits===-Infinity){
		return 0;
	}else if(digits!==digits){
		return NaN;
	}else{
		let pow;
		let value;
		if(digits>0){
			pow=Math.pow(10,digits);
			value=number*pow;
			if(value===Infinity||value===-Infinity){
				return number;
			}else if(digits>22){
				if(value>Number.MAX_SAFE_INTEGER||value<Number.MIN_SAFE_INTEGER){
					const [real,index]=simpleSplitString(number.toString(),'e');
					value=Number(real+'e'+(index?(+index+digits):digits));
				}
				const [real,index]=simpleSplitString(fn(value).toString(),'e');
				return +(real+'e'+(index?(+index-digits):-digits));
			}else{
				return fn(value)/pow;
			}
		}else{
			pow=Math.pow(10,-digits);
			value=number/pow;
			if(value<1&&value>-1){
				return 0;
			}else{
				return fn(value)*pow;
			}
		}
	}
}
/**
 * 四舍五入
 * 把指定实数, 按一定小数位数四舍五入
 * @param number	被四舍五入的实数
 * @param digits	保留的小数位数
 * @return			四舍五入后的值
 */
function numberRound(number:number,digits?:number):number{
	return _decimalAdjust('round',number,digits);
}
/**
 * 向上取整
 * @param number	被取整的数
 * @param digits	取整的小数位数
 * @return			取整后的数
 */
function numberCeil(number:number,digits?:number):number{
	return _decimalAdjust('ceil',number,digits);
}
/**
 * 向下取整
 * @param number	被取整的数
 * @param digits	取整的小数位数
 * @return			取整后的数
 */
function numberFloor(number:number,digits?:number):number{
	return _decimalAdjust('floor',number,digits);
}
//endregion
//region numberAdd、numberAdds
/**
 * 安全加法
 * 浮点数的加减不会出现误差, 例如: 0.1 + 0.2
 * @param p1	相加数1
 * @param p2	相加数2
 * @return		和
 */
function numberAdd(p1:number,p2:number):number{
	return numberRound(p1+p2,Math.max(0,decimalDigits(p1),decimalDigits(p2)));
}
/**
 * 安全加法(多个)
 * 浮点数的加减不会出现误差, 例如: 0.1 + 0.2 + 0.3
 * @param p1	相加数1
 * @param p2	相加数2
 * @param p3	相加数3
 * @param rest	其他相加数
 * @return		和
 */
function numberAdds(p1:number,p2:number,p3:number,...rest:Array<number>):number{
	let maxDecimalDigits=Math.max(0,decimalDigits(p1),decimalDigits(p2),decimalDigits(p3));
	let result=p1+p2+p3;
	for(const p of rest){
		result+=p;
		const val=decimalDigits(p);
		if(val>maxDecimalDigits){
			maxDecimalDigits=val;
		}
	}
	return numberRound(result,maxDecimalDigits);
}
//endregion
//region numberMulti、numberMultis
/**
 * 安全乘法
 * 浮点数的乘除不会出现误差, 例如: 0.1 * 0.9
 * @param p1	相乘数1
 * @param p2	相乘数2
 * @return		乘积
 */
function numberMulti(p1:number,p2:number):number{
	return numberRound(p1*p2,decimalDigits(p1)+decimalDigits(p2));
}
/**
 * 安全乘法(多个)
 * 浮点数的乘除不会出现误差, 例如: 0.1 * 0.9 * 2
 * @param p1	相乘数1
 * @param p2	相乘数2
 * @param p3	相乘数3
 * @param rest	其他相乘数
 * @return			乘积
 */
function numberMultis(p1:number,p2:number,p3:number,...rest:Array<number>):number{
	let maxDecimalDigits=decimalDigits(p1)+decimalDigits(p2)+decimalDigits(p3);
	let result=p1*p2*p3;
	for(const p of rest){
		result*=p;
		maxDecimalDigits+=decimalDigits(p);
	}
	return numberRound(result,maxDecimalDigits);
}
//endregion
//region numberToString
const urlSafeChar='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-';
/**
 * 把数字转换为 'A-Za-z0-9_-'
 * @param num 转换的数字
 * @return 转换后的字符串
 */
function numberToString(num:number):string{
	let res='';
	do{
		res=urlSafeChar[num&63]+res;
		num>>>=6;
	}while(num);
	return res;
}
//endregion
export {
	numberIsFinite,
	numberIsInteger,
	decimalDigits,
	numberRound,
	numberCeil,
	numberFloor,
	numberAdd,
	numberAdds,
	numberMulti,
	numberMultis,
	numberToString,
};